package server.connector.http;

import org.apache.catalina.*;
import org.apache.catalina.net.ServerSocketFactory;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.util.StringManager;
import server.net.DefaultServerSocketFactory;

import java.io.IOException;
import java.net.BindException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;

public class HttpConnector implements Lifecycle, Runnable {


    //连接器线程名,start方法会设置该名
    private String threadName = null;
    //连接器线程
    private Thread thread = null;

    private int bufferSize = Constants.DEFAULT_INPUT_STREAM_BUFFER_SIZE;
    private StringManager sm = StringManager.getManager(Constants.PACKAGE);
    //日志等级
    private int debug = 0;
    //打印日志
    private void log(String message) {
        Logger logger = container.getLogger();
        String localName = threadName;
        if (localName == null)
            localName = "HttpConnector";
        if (logger != null)
            logger.log(localName + " " + message);
        else
            System.out.println(localName + " " + message);
    }
    private void log(String message, Throwable throwable) {

        Logger logger = container.getLogger();
        String localName = threadName;
        if (localName == null)
            localName = "HttpConnector";
        if (logger != null)
            logger.log(localName + " " + message, throwable);
        else {
            System.out.println(localName + " " + message);
            throwable.printStackTrace(System.out);
        }

    }
    //getter------------------------------------------------------------------------------

    public int getDebug() {
        return debug;
    }
    public int getPort() {
        return port;
    }

    public int getBufferSize() {
        return bufferSize;
    }

    //setter------------------------------------------------------------------------------

    //实现Connector接口------------------------------------------------------------------------------
    //servlet容器
    protected Container container = null;
    public Container getContainer() {
        return container;
    }
    public void setContainer(Container container) {
        this.container = container;
    }

    //ServerSocket工厂
    private ServerSocketFactory factory = null;
    //单例模式 factory没加volatile还是不安全
    public ServerSocketFactory getFactory() {
        if (factory == null) {
            synchronized (this) {
                if (factory == null)
                    factory = new DefaultServerSocketFactory();
            }
        }
        return factory;
    }

    //服务器套接字
    private ServerSocket serverSocket;
    //是否初始化过
    private boolean initialized = false;
    //创建ServerSocket对象保存在serverSocket字段,创建失败会报异常
    public void initialize() throws LifecycleException {
        //已经初始化过会报异常
        if (initialized)
            throw new LifecycleException(sm.getString("httpConnector.alreadyInitialized"));
        initialized = true;
        Exception eRethrow = null;
        try {
            //打开套接字
            serverSocket = open();
        } catch (IOException ioe) {
            log("httpConnector, io problem: ", ioe);
            eRethrow = ioe;
        } catch (KeyStoreException kse) {
            log("httpConnector, keystore problem: ", kse);
            eRethrow = kse;
        } catch (NoSuchAlgorithmException nsae) {
            log("httpConnector, keystore algorithm problem: ", nsae);
            eRethrow = nsae;
        } catch (CertificateException ce) {
            log("httpConnector, certificate problem: ", ce);
            eRethrow = ce;
        } catch (UnrecoverableKeyException uke) {
            log("httpConnector, unrecoverable key: ", uke);
            eRethrow = uke;
        } catch (KeyManagementException kme) {
            log("httpConnector, key management problem: ", kme);
            eRethrow = kme;
        }
        //初始化失败,抛出异常
        if (eRethrow != null)
            throw new LifecycleException(threadName + ".open", eRethrow);
    }

    //端口号
    private int port = Constants.DEFAULT_PORT;
    //连接队列长度
    private int acceptCount = Constants.DEFAULT_ACCEPT_COUNT;
    //服务器IP地址,供主机有多个IP地址时选择,为nullServerSocket会监听主机上的所有地址
    private String address = null;
    //根据port,acceptCount,address创建ServerSocket
    //成功返回ServerSocket对象，失败报异常
    private ServerSocket open() throws IOException, KeyStoreException, NoSuchAlgorithmException,
            CertificateException, UnrecoverableKeyException, KeyManagementException {
        ServerSocketFactory factory = getFactory();
        //所有地址都绑定
        if (address == null) {
            log(sm.getString("httpConnector.allAddresses"));
            try {
                return factory.createSocket(port, acceptCount);
            } catch (BindException e) {
                throw new BindException(e.getMessage() + ":" + port);
            }
        }
        //绑定指定地址
        try {
            InetAddress inetAddress = InetAddress.getByName(address);
            log(sm.getString("httpConnector.anAddress", address));
            try {
                return factory.createSocket(port, acceptCount, inetAddress);
            } catch (BindException e) {
                throw new BindException(e.getMessage() + ":" + address + ":" + port);
            }
        } catch (Exception e) {
            log(sm.getString("httpConnector.noAddress", address));
            //绑指定地址失败，绑全部地址
            try {
                return factory.createSocket(port, acceptCount);
            } catch (BindException be) {
                throw new BindException(be.getMessage() + ":" + port);
            }
        }
    }

    public Request createRequest() {
        return null;
    }

    //实现Lifecycle接口------------------------------------------------------------------------------
    protected LifecycleSupport lifecycle = new LifecycleSupport(this);
    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        lifecycle.addLifecycleListener(listener);
    }

    @Override
    public LifecycleListener[] findLifecycleListeners() {
        return lifecycle.findLifecycleListeners();
    }

    @Override
    public void removeLifecycleListener(LifecycleListener listener) {
        lifecycle.removeLifecycleListener(listener);
    }
    //是否启动过
    private boolean started = false;
    //最少HTTP处理器数量
    protected int minProcessors = Constants.DEFAULT_MIN_PROCESSORS;
    //最大HTTP处理器数量 为负数时表示没有数量限制
    private int maxProcessors = Constants.DEFAULT_MAX_PROCESSORS;
    //当前HTTP处理器数量
    private int curProcessors = 0;
    //存放已经创建但未使用的HTTP处理器
    private Deque<HttpProcessor> processors = new LinkedList<>();
    //启动一个线程来处理与客户端连接的任务,并创建最初需要的处理器数
    @Override
    public void start() throws LifecycleException {
        if (started)
            throw new LifecycleException
                    (sm.getString("httpConnector.alreadyStarted"));
        threadName = "HttpConnector[" + port + "]";
        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;
        //创建最初需要的处理器数放到栈中,并启动这些线程
        while (curProcessors < minProcessors) {
            //特殊情况，最少处理器数比最大处理器数多
            if (maxProcessors > 0 && curProcessors >= maxProcessors)
                break;
            recycle(newProcessor());
        }
        //启动连接器线程
        threadStart();
    }


    private void threadStart() {
        log(sm.getString("httpConnector.starting"));
        thread = new Thread(this, threadName);
        //设置为守护线程
        thread.setDaemon(true);
        thread.start();
    }
    private ArrayList<HttpProcessor> created = new ArrayList<>();
    //创建HTTP处理器,调用其生命周期方法,将他放到created列表中
    private HttpProcessor newProcessor() {
        HttpProcessor processor = new HttpProcessor(this, curProcessors++);
        if (processor instanceof Lifecycle) {
            try {
                //启动处理器自己的线程
                ((Lifecycle)processor).start();
            } catch (LifecycleException e) {
                log("newProcessor", e);
                return null;
            }
        }
        created.add(processor);
        return processor;
    }
    //重复利用处理器
    void recycle(HttpProcessor processor) {
        //可能有多个处理器线程同时调用,要加锁
        synchronized (processors) {
            processors.push(processor);
        }
    }
    //未实现
    @Override
    public void stop() throws LifecycleException {

    }

    //实现Runnable接口------------------------------------------------------------------------------
    private boolean stopped = false;
    private int connectionTimeout = Constants.DEFAULT_CONNECTION_TIMEOUT;
    private boolean tcpNoDelay = true;
    private Object threadSync = new Object();
    @Override
    public void run() {
        while (!stopped) {
            Socket socket = null;
            try {
                socket = serverSocket.accept();
                if (connectionTimeout > 0) {
                    //设置阻塞时间,read阻塞时间超出该值时,会报java.net.SocketTimeoutException异常
                    //单位为毫秒
                    socket.setSoTimeout(connectionTimeout);
                }
                //如果Nagle算法关闭,对于小数据包,比如一次鼠标移动,点击,客户端都会立马和服务端交互，实时响应度非常高，但频繁的通信却很占用不少网络资源。
                //如果Nagle算法开启,算法会自动合并小数据包,等到达到一定大小（MSS）后,才会和服务端交互,优点是减少了通信次数,缺点是实时响应度会低一些。
                //Socket创建时,默认是开启Nagle算法的,可以根据实时性要求来选择是否关闭Nagle算法。
                //当前选择关闭Nagle算法
                socket.setTcpNoDelay(tcpNoDelay);
            } catch (AccessControlException ace) {
                //public static void checkPermission(Permission perm) throws AccessControlException
                //调用accept方法可能会出现该异常,连接失败,等待下一个连接(应该只是连接失败,serverSocket没问题)
                log("socket accept security exception", ace);
                continue;
            } catch (IOException e) {
                //其他异常(应该是serverSocket没问题出现问题,要重新打开)
                try {
                    //不懂为啥加锁
                    synchronized (threadSync) {
                        if (started && !stopped) {
                            log("accept error: ", e);
                        }
                        if (!stopped) {
                            serverSocket.close();
                            serverSocket = open();
                        }
                    }
                //重新打开过程中出错,跳出循环
                } catch (IOException ioe) {
                    log("socket reopen, io problem: ", ioe);
                    break;
                } catch (KeyStoreException kse) {
                    log("socket reopen, keystore problem: ", kse);
                    break;
                } catch (NoSuchAlgorithmException nsae) {
                    log("socket reopen, keystore algorithm problem: ", nsae);
                    break;
                } catch (CertificateException ce) {
                    log("socket reopen, certificate problem: ", ce);
                    break;
                } catch (UnrecoverableKeyException uke) {
                    log("socket reopen, unrecoverable key: ", uke);
                    break;
                } catch (KeyManagementException kme) {
                    log("socket reopen, key management problem: ", kme);
                    break;
                }
                //重新打开成功,重新开始等待连接
                continue;
            }
            //建立连接成功，开始处理连接
            //获取处理器
            HttpProcessor processor = createProcessor();
            //处理器个数达到最大数,没用可用的处理器了,直接关闭连接
            if (processor == null) {
                try {
                    log(sm.getString("httpConnector.noProcessor"));
                    socket.close();
                } catch (IOException e) {

                }
                //等待下次连接
                continue;
            }
            //将processor唤醒,处理请求
            processor.assign(socket);
        }
        //不懂
        synchronized (threadSync) {
            threadSync.notifyAll();
        }
    }
    //当栈中有处理器可用时，从栈里拿，否则若可以再创建新处理器，则创建返回，否则返回null
    private HttpProcessor createProcessor() {
        //连接器拿时处理器可能往里放,要加锁
        synchronized (processors) {
            //栈里的处理器没用完,直接拿来用
            if (processors.size() > 0) {
                return processors.pop();
            }
            //限制最大处理器数并且当前未达到最大数,新创建一个处理器
            if (maxProcessors > 0 && curProcessors < maxProcessors) {
                return newProcessor();
            } else {
                //无限制创建处理器数
                if (maxProcessors < 0)
                    return newProcessor();
                else
                    //有限制创建且达到最大限制
                    return null;
            }
        }
    }
}
